package com.martin.lib_base.utils

import com.martin.lib_base.bean.SocketEventBean
import com.martin.lib_base.constant.ConstantBus
import com.martin.lib_base.impl.FlowBus
import com.martin.lib_base.impl.HttpLogImpl
import com.martin.lib_base.ktx.loge
import com.martin.lib_base.net.Api
import com.martin.lib_base.net.NetApply
import dev.utils.app.HandlerUtils
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okhttp3.internal.ws.RealWebSocket
import okhttp3.logging.HttpLoggingInterceptor
import java.util.Objects
import java.util.concurrent.TimeUnit
import kotlin.properties.Delegates

/**
 * @author：Houge
 * @date：2023/4/18
 * @desc：websocket工具类
 */
object WebSocketUtil {

    private const val TAG = "WebSocketUtil"

    // 连接超时时间(S)
    private const val TIMEOUT = 30L

    // OkHttpClient对象
    private val okHttpClient: OkHttpClient

    // WebSocket对象
    private var webSocket: WebSocket? = null

    // WebSocket是否连接
    private var connectState = false

    // 重连次数
    private var retryCount = 5

    // WebSocket监听
    private val webSocketListener = object : WebSocketListener() {
        override fun onOpen(webSocket: WebSocket, response: okhttp3.Response) {
            showLog("onOpen")
            retryCount = 3
            connectState = true
            sendHeartBeat()
        }

        override fun onMessage(webSocket: WebSocket, text: String) {
            if (text == "pong") return
            showLog("onMessage: $text")

            // 解析消息
            val eventBean = NetApply.gson.fromJson(text, SocketEventBean::class.java)
            // 事件总线发送消息
            FlowBus.with<SocketEventBean>(eventBean.event)
                .tryEmit(eventBean)
        }

        override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
            showLog("onClosed: $code, $reason")
            closeWebSocket()
        }

        override fun onFailure(webSocket: WebSocket, t: Throwable, response: okhttp3.Response?) {
            showLog("onFailure: ${t.message}")
            if (retryCount > 0) {
                connect()
                retryCount--
            } else {
                closeWebSocket()
            }
        }
    }

    // 心跳Runnable
    private val heartBeatRunnable = Runnable {
        sendMsg("ping")
        sendHeartBeat()
    }

    init {
        val logInterceptor = HttpLoggingInterceptor(HttpLogImpl())
        logInterceptor.level = HttpLoggingInterceptor.Level.BODY

        okHttpClient = OkHttpClient.Builder()
            .readTimeout(TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
            .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .addInterceptor(logInterceptor)
            .build()
    }

    /**
     * 创建WebSocket对象
     */
    private fun createWebSocket() {
        val url = Api.BASE_URL
            .replace("http://", "ws://")
            .replace("https://", "wss://")
            .plus("ws")
        val request = Request.Builder().url(url).build()
        webSocket = okHttpClient.newWebSocket(request, webSocketListener)
    }

    /**
     * 连接WebSocket
     */
    fun connect() {
        if (!connectState) {
            createWebSocket()
        }
    }

    /**
     * 发送心跳
     */
    private fun sendHeartBeat() {
        HandlerUtils.postRunnable(heartBeatRunnable, 5000)
    }

    /**
     * 停止心跳
     */
    fun stopHeartBeat() {
        HandlerUtils.removeRunnable(heartBeatRunnable)
    }

    /**
     * 发送消息
     */
    fun sendMsg(msg: String) {
        val isSend = webSocket?.send(msg)
        if (isSend == true && msg == "ping") return
        showLog("发送消息：$msg, 是否发送成功：$isSend")
    }

    /**
     * 关闭WebSocket
     */
    fun closeWebSocket() {
        stopHeartBeat()
        webSocket?.close(1000, "主动关闭")
        webSocket = null
        connectState = false
    }

    private fun showLog(msg: String) {
        loge("$TAG : $msg")
    }
}